#ifndef GAMEMODEL_H
#define GAMEMODEL_H

/*
 * 其中算法包括博弈树与极大极小搜索 α-β剪枝 启发函数
 * 参考文章：https://blog.csdn.net/qq_44732921/article/details/104068832#comments_15742963
 * 只算一步的评估函数参考：https://blog.csdn.net/u011587401/article/details/50877828以及https://www.bilibili.com/video/BV1np4y1x7BG
 * 启发函数计分参考：https://www.jianshu.com/p/0cfc00ff9cf6
 * 其他，比如成五 活四等棋局情况参考：https://blog.csdn.net/marble_xu/article/details/90450436
 * 其他：https://blog.csdn.net/lihongxun945/article/details/50668622
*/
//-----五子棋游戏模型类-----
#include <vector>
#include <array>
#include <iostream>


//局面评估
#define CHENG_5_SCORE   5000000
#define HUO_4_SCORE   100000
#define CHONG_4_SCORE   10000
#define DAN_HUO_3_SCORE   8000
#define TIAO_HUO_3_SCORE   7000
#define MIAN_3_SCORE   500
#define HUO_2_SCORE   50
#define MIAN_2_SCORE   10
//局面
//成五
//5000000分
//活四
//100000分
//冲四
//10000分
//单活三
//8000分
//跳活三
//7000分
//眠三
//500分
//活二
//50分
//眠二
//10分
#define CHENG_5_STRING   "11111"
#define HUO_4_STRING   "011110"
#define CHONG_4_STRING_1_1   "01111-"
#define CHONG_4_STRING_1_2   "-11110"
#define CHONG_4_STRING_2_1   "10111"
#define CHONG_4_STRING_2_2   "11101"
#define CHONG_4_STRING_3   "11011"
#define DAN_HUO_3_STRING   "01110"
#define TIAO_HUO_3_STRING_1_1   "1011"
#define TIAO_HUO_3_STRING_1_2   "1101"
#define MIAN_3_1_1   "00111-"
#define MIAN_3_1_2   "-11100"
#define MIAN_3_2_1   "01011-"
#define MIAN_3_2_2   "-11010"
#define MIAN_3_3_1   "01101-"
#define MIAN_3_3_2   "-10110"
#define MIAN_3_4_1   "10011"
#define MIAN_3_4_2   "11001"
#define MIAN_3_5   "10101"
#define MIAN_3_6   "-01110-"
#define HUO_2_STRING_1   "001100"
#define HUO_2_STRING_2   "01010"
#define HUO_2_STRING_3   "1001"
#define MIAN_2_1_1   "00011-"
#define MIAN_2_1_2   "-11000"
#define MIAN_2_2_1   "00101-"
#define MIAN_2_2_2   "-10100"
#define MIAN_2_3_1   "01001-"
#define MIAN_2_3_2   "-10010"
#define MIAN_2_4   "10001"


//游戏类型，双人还是AI(目前固定AI下白子)
enum GameType
{
    MAN,
    AI  //人机
};

//游戏状态
enum GameStatus
{
    PLAYING,
    WIN,
    DEAD
};
//五元组
struct pointAndScore{
    int xpoint;
    int ypoint;
    int score;
};

typedef int fivePoints[5][2] ;

//棋盘尺寸
const int BOARD_GRAD_SIZE = 15;

const int MARGIN = 30; //棋盘边缘空隙
const int CHESS_RADIUS = 15; //棋子半径
const int MARK_SIZE = 6;//落子标记边长
const int BLOCK_SIZE = 40;//格子的大小
const int POS_OFFSET = BLOCK_SIZE * 1/3;//20 鼠标点击的模糊距离上限

const int AI_THINK_TIME = 700;//AI下棋的思考时间 假时间 落子时间

//权重 局面评估
const int PosValue[BOARD_GRAD_SIZE][BOARD_GRAD_SIZE] =
{
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
    {0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0},
    {0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0},
    {0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0},
    {0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0},
    {0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0},
    {0, 1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 0},
    {0, 1, 2, 3, 4, 5, 6, 6, 6, 5, 4, 3, 2, 1, 0},
    {0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0},
    {0, 1, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, 0},
    {0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0},
    {0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0},
    {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};


class GameModel
{
public:
    GameModel();
public:
    void startGame(GameType type); //开始游戏
    void calculateScore(int chessColor); //计算评分
    void calculateScoreNew(int chessColor); //计算评分 -使用五元组和新的评分方式
    void searchMaxScore();//查找分值最大值
    pointAndScore getMaxEvaluate(int leftStep, int color);//决策 极大极小
    pointAndScore getMaxEvaluate(int leftStep, int color, int passValue);//决策 极大极小+alpha-beta剪枝
    pointAndScore getMaxEvaluate2(int leftStep, int color, int passValue);//决策 极大极小+alpha-beta剪枝+启发式搜索
    int evaluatePoint(int xpos,int ypos,int color); //整体局面的评估值 启发式搜索
    int f(int xpos,int ypos,int color);//每一个位置评估
    void actionByPerson(int row, int col); //人执行下棋
    void actionByAI(int &clickRow, int &clickCol);//机器下棋
    void actionByAI2(int &clickRow, int &clickCol);//机器下棋  加入极大极小搜索
    void updateGameMap(int row, int col);//每次落子后，更新游戏棋盘
    bool isWin(int row, int col);//判断游戏是否胜利
    bool isDeadGame();//判断是否和棋

    //判定 行列在范围内
    bool isInRange(int row,int col);
public:
    //存储当前游戏棋盘和棋子的情况，空白为0，黑子1，白子-1
    std::vector<std::vector<int>> gameMapVec;

    //存储各个点位的评分情况，作为AI下棋依据
    std::vector<std::vector<int>> scoreMapVec;
    //记录最高得分的点位置
    std::vector<std::vector<int>> maxpoint;  //std::vector<std::pair<int,int>> maxPoints;
    //判断是否赢 八个方向的增量表
    int incretDatas[8][2];

    //五元组和计分
    std::vector<std::vector<std::vector<int>>> fiveGroups;//std::vector<std::vector<int>>

    //标示下棋方，true:黑棋方  false: AI白棋方（AI）
    bool playerFlag;

    GameType gameType;//游戏模式：人机对弈，还是双人
    GameStatus gameStatus;//游戏状态

    int AICount;


};
#endif // GAMEMODEL_H
